/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package gui;

import gui.usergui.ResultFrame;
import gui.usergui.SaveExpFrame;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.util.ArrayList;
import javax.swing.DefaultListModel;
import javax.swing.JList;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeExpansionListener;
import javax.swing.plaf.basic.BasicTreeUI;
import javax.swing.tree.TreePath;
import org.math.plot.PlotPanel;
import org.math.plot.plots.LinePlot;
import org.math.plot.plots.Plot;
import org.math.plot.utils.Array;
import stendcontrol.DataSensor;
import stendcontrol.Experiment;
import stendcontrol.ExperimentContainer;
import stendcontrol.Func;
import stendcontrol.SaveLoadExpContainer;

/**
 *
 * @author minaev
 */
public class ViewerExperimentsModel implements WindowListener {

    private ExperimentContainer exp_cont;
    private SaveLoadExpContainer sl_exp_cont;
    private PlotPanel plot;
    private ExperimentTreeModel exp_tree_model;
    private DefaultListModel<Object> list_model = new DefaultListModel<Object>();
    private JTree j_tree;
    private ArrayList<TreePath> added_funcs = new ArrayList<TreePath>();
    private ArrayList<Plot> plot_added = new ArrayList<Plot>();
    private ArrayList<Color> plot_colors = new ArrayList<Color>();
    private JList leg_list;
    private LegendListCellRender leg_cell_render =
            new LegendListCellRender(plot_colors);
    private JPopupMenu exp_popup_mnu = new JPopupMenu();
    private JMenuItem save_item = new JMenuItem("Сохранить");
    private JMenuItem view_result_item = new JMenuItem("Результаты");
    private JMenuItem close_item = new JMenuItem("Закрыть");
    public final static Color[] COLORLIST = {Color.RED, Color.GREEN,
        Color.ORANGE, Color.PINK, Color.CYAN, Color.MAGENTA};

    public ViewerExperimentsModel(ExperimentContainer exp_cont,
            SaveLoadExpContainer sl_exp_cont,
            JTree j_tree, PlotPanel plot, JList leg_list) {
        this.exp_cont = exp_cont;
        this.sl_exp_cont = sl_exp_cont;
        this.j_tree = j_tree;
        this.plot = plot;
        this.leg_list = leg_list;
        exp_tree_model = new ExperimentTreeModel(exp_cont);
        j_tree.setModel(exp_tree_model);
        j_tree.addMouseListener(exp_tree_mouselistener);
        j_tree.addTreeExpansionListener(null);
        j_tree.addTreeExpansionListener(exp_tree_expanlistener);
        leg_list.setModel(list_model);
        leg_list.addMouseListener(leg_list_mouse_listener);
        leg_list.setCellRenderer(leg_cell_render);
        this.exp_cont.addListener(exp_tree_model);

        save_item.addActionListener(al_save_item);
        view_result_item.addActionListener(al_view_result_item);
        close_item.addActionListener(al_close_item);

        exp_popup_mnu.add(save_item);
        exp_popup_mnu.add(view_result_item);
        exp_popup_mnu.add(close_item);
        j_tree.setComponentPopupMenu(exp_popup_mnu);
    }
    MouseListener exp_tree_mouselistener = new MouseListener() {
        @Override
        public void mousePressed(MouseEvent e) {
            if (e.isPopupTrigger()) {
                int selRow = j_tree.getRowForLocation(e.getX(), e.getY());
                TreePath selPath = j_tree.getPathForLocation(e.getX(), e.getY());
                if (selRow != -1) {
                }
            } else if (e.getClickCount() == 2) {
                int selRow = j_tree.getRowForLocation(e.getX(), e.getY());
                TreePath selPath = j_tree.getPathForLocation(e.getX(), e.getY());
                if (selRow != -1) {
                    if (selPath.getPath()[selPath.getPath().length - 1]
                            .getClass() == Func.class) {
                        Func afc =
                                (Func) selPath.
                                getPath()[selPath.getPath().length - 1];
                        processFunc(afc, selPath);
                    }
                }
            }
            /*else if (e.getClickCount() == 1) {
             int selRow = j_tree.getRowForLocation(e.getX(), e.getY());
             TreePath selPath = j_tree.getPathForLocation(e.getX(), e.getY());
             if (selRow != -1) {
             if (selPath.getPath()[selPath.getPath().length - 1]
             .getClass() == DataSensor.class) {
             exp_tree_model.updatePath(selPath.getPath());
             }
             }

             }*/
        }

        @Override
        public void mouseClicked(MouseEvent e) {
        }

        @Override
        public void mouseReleased(MouseEvent e) {
        }

        @Override
        public void mouseEntered(MouseEvent e) {
        }

        @Override
        public void mouseExited(MouseEvent e) {
        }
    };
    TreeExpansionListener exp_tree_expanlistener = new TreeExpansionListener() {
        @Override
        public void treeExpanded(TreeExpansionEvent event) {
            exp_tree_model.updatePath(event.getPath().getPath());
        }

        @Override
        public void treeCollapsed(TreeExpansionEvent event) {
        }
    };
    MouseListener leg_list_mouse_listener = new MouseListener() {
        @Override
        public void mousePressed(MouseEvent e) {
            if (e.getClickCount() == 2) {
                int ind = leg_list.getSelectedIndex();
                if (ind != -1) {
                    removeFunc(ind);
                }
            }
        }

        @Override
        public void mouseClicked(MouseEvent e) {
        }

        @Override
        public void mouseReleased(MouseEvent e) {
        }

        @Override
        public void mouseEntered(MouseEvent e) {
        }

        @Override
        public void mouseExited(MouseEvent e) {
        }
    };
    ActionListener al_save_item = new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            if (getSelectedExp() != null) {
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        new SaveExpFrame(getSelectedExp(),sl_exp_cont)
                                .setVisible(true);
                    }
                });
            }
        }
    };
    ActionListener al_view_result_item = new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            if (getSelectedExp() != null) {
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        new ResultFrame(getSelectedExp()).setVisible(true);
                    }
                });
            }
        }
    };
    ActionListener al_close_item = new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            Experiment s_exp = getSelectedExp();
            if (s_exp != null) {
                int d_res = JOptionPane.YES_OPTION;
                if (!s_exp.isSaved()) {
                    d_res = JOptionPane.showConfirmDialog(null, "Эксперимент не сохранен. Закрыть?", "Подтверждение",
                            JOptionPane.YES_NO_OPTION);
                }
                if (d_res == JOptionPane.YES_OPTION) {
                    exp_cont.removeExp(s_exp);
                }
            }
        }
    };

    private void processFunc(Func afc, TreePath selPath) {
        if (added_funcs.contains(selPath)) {
            int ind = added_funcs.indexOf(selPath);
            removeFunc(ind);
        } else {
            added_funcs.add(selPath);

            double[] x;
            if (afc.getArgs().length == 0) {
                x = Array.increment(
                        afc.getValues().length, afc.getBegin(), afc.getSamp());
            } else {
                x = afc.getArgs();
            }

            plot_colors.add(getNewColor());
            Plot a_plot = new LinePlot(afc.getName(),
                    plot_colors.get(plot_colors.size() - 1),
                    Array.mergeColumns(x, afc.getValues()));
            plot_added.add(a_plot);
            plot.addPlot(a_plot);
            String rt_string = "";
            for (int i = 1; i < selPath.getPath().length; i++) {
                rt_string += selPath.getPath()[i].toString() + ">";
            }
            rt_string = rt_string.substring(0, rt_string.length() - 1);
            list_model.addElement(rt_string);
        }
    }

    private void removeFunc(int ind) {
        list_model.remove(ind);
        plot.removePlot(plot_added.get(ind));
        plot.repaint();
        added_funcs.remove(ind);
        plot_added.remove(ind);
        plot_colors.remove(ind);
    }

    public ExperimentTreeModel getExpTreeModel() {
        return exp_tree_model;
    }

    public DefaultListModel<Object> getListModel() {
        return list_model;
    }

    public MouseListener getExpTreeMouseListener() {
        return exp_tree_mouselistener;
    }

    protected Color getNewColor() {
        return COLORLIST[plot.plotCanvas.plots.size()
                % COLORLIST.length];
    }

    public void close() {
        exp_cont.removeListener(exp_tree_model);
    }

    @Override
    public void windowClosed(WindowEvent e) {
        close();
    }

    @Override
    public void windowOpened(WindowEvent e) {
    }

    @Override
    public void windowClosing(WindowEvent e) {
    }

    @Override
    public void windowIconified(WindowEvent e) {
    }

    @Override
    public void windowDeiconified(WindowEvent e) {
    }

    @Override
    public void windowActivated(WindowEvent e) {
    }

    @Override
    public void windowDeactivated(WindowEvent e) {
    }

    public Experiment getSelectedExp() {
        if (j_tree.getSelectionPath() != null) {
            Object[] cur_path = j_tree.getSelectionPath().getPath();
            if (cur_path.length != 0) {
                if (cur_path[cur_path.length - 1].getClass() == Experiment.class) {
                    return (Experiment) cur_path[cur_path.length - 1];
                } else {
                    return null;
                }
            } else {
                return null;
            }
        } else {
            return null;
        }
    }
}
